// NitroFile.cs:
// Nitro (Nintendo DS) file.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License.
// See LICENSE for more information.

using System;
using System.Collections.Generic;

namespace SharpNitroLib.NARC
{
	/// <summary>
	/// Nitro (Nintendo DS) file.
	/// </summary>
    public class NitroFile
    {
    	/// <summary>
    	/// Frames of Nitro file.
    	/// </summary>
        private readonly List<NitroFileFrame> _frames = new List<NitroFileFrame>();
        /// <summary>
        /// Header of Nitro file.
        /// </summary>
        private readonly NitroFileHeader _header = new NitroFileHeader();
        /// <summary>
        /// Filetype (magic bytes).
        /// </summary>
        private UInt32 _fileType;

		/// <summary>
    	/// Frames of Nitro file.
    	/// </summary>
        public NitroFileFrame[] Frames
        {
            get
            {
                return _frames.ToArray();
            }
        }

        /// <summary>
        /// Filetype (magic bytes).
        /// </summary>
        public UInt32 FileType
        {
            get {
                return _header.FileType;
            }
            set {
                _header.FileType = value;
            }
        }

        /// <summary>
        /// Called when size of frame changes.
        /// </summary>
        /// <param name="nitroFileFrame">Changed frame.</param>
        /// <param name="newSize">New size of frame.</param>
        private void OnFrameSizeChanged(NitroFileFrame nitroFileFrame, UInt32 newSize)
        {
            CalculateFileSize();        
        }

        /// <summary>
        /// Add frame to Nitro file.
        /// </summary>
        /// <param name="frame">Frame to add.</param>
        public void AddFrame(NitroFileFrame frame)
        {
            if (null == frame)
                return;
            if (_frames.Contains(frame))
            	return;
            _frames.Add(frame);
            frame.FrameSizeChanged += this.OnFrameSizeChanged;
            CalculateFileSize();
        }

        /// <summary>
        /// Remove frame from Nitro file.
        /// </summary>
        /// <param name="frame">Frame to remove.</param>
        public void RemoveFrame(NitroFileFrame frame)
        {
        	if (null == frame)
                return;
        	if (!_frames.Contains(frame))
        		return;
            frame.FrameSizeChanged -= this.OnFrameSizeChanged;
            _frames.Remove(frame);
            CalculateFileSize();
        }

        /// <summary>
        /// Remove frame from Nitro file at index.
        /// </summary>
        /// <param name="index">Index of frame to remove.</param>
        public void RemoveFrameAt(int index)
        {
            if (0 > index || _frames.Count < index)
                throw new InvalidOperationException("Invalid index for NitroFileFrame.");
            _frames.RemoveAt(index);
            CalculateFileSize();
            
        }

        /// <summary>
        /// Calculate size of file.
        /// </summary>
        private void CalculateFileSize()
        {
            UInt32 fileSize = 0;
            fileSize += _header.HeaderSize;
            for (var i = 0; i < this.Frames.Length; ++i)
                fileSize += this._frames[i].FrameSize;
            _header.FileSize = fileSize;
        }

        /// <summary>
        /// Filesize.
        /// </summary>
        public UInt32 FileSize
        {
            get
            {
                return _header.FileSize;
            }
        }
    }
}